#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QSerialPortInfo>
#include <QStandardItemModel>
#include <QList>
#include <QMetaEnum>
#include <QScrollBar>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow), _msp(nullptr)
{
    ui->setupUi(this);
    init();
}

MainWindow::~MainWindow()
{
    delete ui;
    if (_file.isOpen())
        _file.close();
}

/// @brief 主窗口初始化
void MainWindow::init()
{
    // 初始化 串口ComboBox
    init_cmb_sp();

    // 初始化 其他ComboBox
    OptionSet::initComboBox(ui->cmb_baudrate, OptionSet::SP_BaudRate);
    OptionSet::initComboBox(ui->cmb_databits, OptionSet::SP_DataBits);
    OptionSet::initComboBox(ui->cmb_parity, OptionSet::SP_Parity);
    OptionSet::initComboBox(ui->cmb_stopbits, OptionSet::SP_StopBits);

    // 设置可以控制ui上的串口参数
    setSPContolStatus(true);

    // 指定文档可能具有的最大块数。如果文档中有更多使用此属性指定的块，则将从文档开头删除块。
    ui->pe_history->setMaximumBlockCount(1000);
    ui->chk_hexreceive->setChecked(true);

    // 打开文件
    _file.setFileName("myrs485log.txt");
    _file.open(QIODevice::WriteOnly | QIODevice::Append);
}

/// @brief 初始化 串口combo box
void MainWindow::init_cmb_sp()
{
    QStandardItemModel *spModel = new QStandardItemModel(ui->cmb_sp);
    const QList<QSerialPortInfo> spl = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &info : spl)
    {
        QStandardItem *item = new QStandardItem(info.portName());
        item->setToolTip(info.portName() + " " + info.description());
        spModel->appendRow(item);
    }

    ui->cmb_sp->clear();
    ui->cmb_sp->setModel(spModel);
}

/// @brief 从ui界面获取串口设置参数，并对传入的参数赋值
/// @param setting
/// @return 异常返回值<0  正常返回0
int MainWindow::getSPSetting(MySerialPortSettings &setting)
{
    QString portName = ui->cmb_sp->currentText();
    if (portName.isEmpty())
        return -1;
    if (ui->cmb_baudrate->currentIndex() < 0)
        return -2;
    if (ui->cmb_databits->currentIndex() < 0)
        return -3;
    if (ui->cmb_parity->currentIndex() < 0)
        return -4;
    if (ui->cmb_stopbits->currentIndex() < 0)
        return -5;

    setting.portName = portName;
    setting.baudRate = QSerialPort::BaudRate(ui->cmb_baudrate->currentData().toInt());
    setting.dataBits = QSerialPort::DataBits(ui->cmb_databits->currentData().toInt());
    setting.parity = QSerialPort::Parity(ui->cmb_parity->currentData().toInt());
    setting.stopBits = QSerialPort::StopBits(ui->cmb_stopbits->currentData().toInt());

    return 0;
}

/// @brief 设置打开串口按钮的图标、是否可以控制ui上的串口参数；当串口打开或者关闭时，对应ui上的控件进行使能失能
/// @param state 可控 true 不可控 false
void MainWindow::setSPContolStatus(bool state)
{
    ui->cmb_sp->setEnabled(state);
    ui->cmb_baudrate->setEnabled(state);
    ui->cmb_databits->setEnabled(state);
    ui->cmb_parity->setEnabled(state);
    ui->cmb_stopbits->setEnabled(state);
    ui->chk_hexreceive->setEnabled(state);

    QString radioStyleSheet = QString("QPushButton{"
                                      "color:black;"
                                      "background-color:transparent;"
                                      "border:1px solid gray;"
                                      "}"
                                      "");
    QString text;
    QString iconPath;
    if (state)
    {
        iconPath = ":/pics/start.png";
        text = tr("open");
    }
    else
    {
        iconPath = ":/pics/stop.png";
        text = tr("close");
    }
    ui->btn_oc->setStyleSheet(radioStyleSheet);
    ui->btn_oc->setIconSize(QSize(32, 32));
    ui->btn_oc->setIcon(QIcon(iconPath));
    ui->btn_oc->setText(text);
}

/*
// bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
//{
//     Q_UNUSED(eventType)
//     Q_UNUSED(result)

//    MSG* msg = reinterpret_cast<MSG*>(message);
//    if (msg->message == WM_DEVICECHANGE)//发生硬件热插拔事件，更新可用串口号
//    {
//        init_cmb_sp();
//    }
//    return false;
//}
*/

// 点击打开按钮
void MainWindow::on_btn_oc_clicked()
{
    if (_msp != nullptr)
    { // 打开-->关闭
        timerRegular->deleteLater();
        _msp->deleteLater();
        _msp = nullptr;
        setSPContolStatus(true);

        ui->pe_history->appendPlainText(tr("port has closed !"));
    }
    else
    { // 关闭-->打开
        // 新建定时器
        timerRegular = new QTimer;
        timerRegular->setTimerType(Qt::PreciseTimer); // 设置为精准定时器

        // 得到串口参数
        MySerialPortSettings setting;
        int rt = getSPSetting(setting);
        if (rt < 0)
        {
            ui->pe_history->appendPlainText(tr("parameter error!"));
            return;
        }
        // 新建我的串口
        RES res;
        _msp = new MySerialPort(setting, res);
        if (res.returnCode < 0) // 打开异常
        {
            timerRegular->deleteLater();
            _msp->deleteLater();
            _msp = nullptr;
            ui->pe_history->appendPlainText(tr("failed to create SerialPort:") + res.msg);
            return;
        }
        else // 正常打开
        {
            setSPContolStatus(false);
            ui->pe_history->appendPlainText(tr("open port!"));
            connect(_msp, &MySerialPort::sgSPReceiveData, this, &MainWindow::slSPReceiveData, Qt::QueuedConnection);
            connect(this, &MainWindow::sgSendData, _msp, &MySerialPort::slSendData, Qt::QueuedConnection);
            connect(timerRegular, &QTimer::timeout, this, &MainWindow::on_btn_send_clicked);
        }
    }
}

void MainWindow::slSPReceiveData(const QByteArray data)
{
    // ui->pe_history->insertPlainText(data.toHex());
    //    if(ui->pe_history->blockCount()>2000)
    //    {

    //    }
    if (_isHex == true) // 展示16进制
    {
        // qDebug()<<data.toHex();

        // 转化为16进制
        ui->pe_history->insertPlainText(data.toHex());

        _file.write(data.toHex()); // 写文件
    }
    else // 展示文本
    {
        // qDebug()<<data;
        ui->pe_history->insertPlainText(data);

        _file.write(data); // 写文件
    }

    // 移动滚动条到底部，实时展示出最新数据
    ui->pe_history->moveCursor(QTextCursor::End);
}

void MainWindow::on_btn_send_clicked()
{
    QString data = ui->pe_send->toPlainText();
    emit sgSendData(data);
}

void MainWindow::on_chk_hexreceive_clicked(bool checked)
{
    _isHex = checked;
}

void MainWindow::on_ckbxRegular_toggled(bool checked)
{
    if (checked == true)
    {
        timerRegular->start(ui->spinBox->value());
    }
    else
    {
        timerRegular->stop();
    }
}

void MainWindow::on_spinBox_valueChanged(int arg1)
{
    timerRegular->setInterval(arg1);
}
